﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Av.Utils;

namespace JrSnifTest
{
    public class TcpHeader
    {

        public int IpHeaderLength { get; set; }

        public int SourcePort { get; set; }

        public int DestinationPort { get; set; }

        public static TcpHeader Parse(byte[] buf)
        {
            return Parse(buf, 0, buf.Length);
        }

        public static TcpHeader Parse(byte[] buf, int offset, int total)
        {
            TcpHeader t = new TcpHeader();
            // Set length of IP header, where TCP is
            t.IpHeaderLength = total;

            MemoryStreamEx ms = new MemoryStreamEx(buf, offset, total);
            byte[] ba;
            byte b;

            ba = ms.Read(2);
            Log4cs.Log("2 bytes of source port: {0}", Common.EncodeHex(ba));
            t.SourcePort = ((ba[0] << 8) & 0xFF00) | ba[1];
            Log4cs.Log("Source port is: {0}", t.SourcePort);

            ba = ms.Read(2);
            Log4cs.Log("2 bytes of destination port: {0}", Common.EncodeHex(ba));
            t.DestinationPort = ((ba[0] << 8) & 0xFF00) | ba[1];
            Log4cs.Log("Destination port is: {0}", t.DestinationPort);

            // Sequence numbert 4 bytes
            ba = ms.Read(4);
            Log4cs.Log("SEQ: {0}", Common.EncodeHex(ba));

            // Acknowledge number 4 bytes
            ba = ms.Read(4);
            Log4cs.Log("ACK: {0}", Common.EncodeHex(ba));


            // Data offset 4 bits + 4 reserved bits
            ba = ms.Read(2);
            Log4cs.Log(Importance.Debug, "2 bytes of data offset and reserved: {0}", Common.EncodeHex(ba));
            int dataOffset = (int)(ba[0] >> 4);
            Log4cs.Log("Data offset is: {0} * 32 = {1} bits", dataOffset, dataOffset * 32);

            // Window size 2 bytes
            ba = ms.Read(2);

            // Checksum 2 bytes
            ba = ms.Read(2);

            // Urgent pointer (if URG set) 2 bytes
            ba = ms.Read(2);

            // Options + padding
            if(dataOffset > 5)
            {
                ba = ms.Read(dataOffset * 4);
                Log4cs.Log("TCP options: {0}", Common.EncodeHex(ba));
            } else
            {
                b = (byte)ms.ReadByte();
                Log4cs.Log("TCP options 1 byte: 0x{0:X}", b);
            }

            int tcpHeaderLength = dataOffset * 4;
            int tcpDataLength = t.IpHeaderLength - tcpHeaderLength - 3;
            Log4cs.Log("Size of TCP data header is {0} bytes...", tcpHeaderLength);
            Log4cs.Log("Size of TCP data is {0} bytes...", tcpDataLength);

            if( tcpDataLength > 0 )
            {
                ba = ms.Read(tcpDataLength);
                //Log4cs.Log("TCP data: {0}", Common.EncodeHex(ba));
                //Log4cs.Log("TCP data: {0}", Encoding.UTF8.GetString(ba));
            }

            return t;
        }

    }
}
